<template>
  <a-modal
    v-model:open="show"
    title="拆分类目"
    width="90%"
    @ok="confirm"
    :after-close="afterClose"
    :ok-button-props="{
      disabled:
        splits.length < 2 ||
        optionMap.size == 0 ||
        optionMap.size != currentCondition.spec_options?.length,
    }"
  >
    <div
      class="grid grid-cols-2 gap-x-4 max-h-[calc(100vh-280px)] overflow-y-auto"
    >
      <div>
        <a-form>
          <a-form-item label="源类目" v-bind="validateInfos.categoryId">
            <a-select
              allow-clear
              placeholder="请选择"
              v-model:value="formRef.categoryId"
              show-search
              @change="changeCategory"
              :disabled="isEdit"
              option-filter-prop="title"
            >
              <a-select-option
                v-for="item in categoryList"
                :key="item"
                :value="item.id"
                :title="item.categoryName"
                :disabled="item.split"
              >
                {{ item.categoryName }}
              </a-select-option>
            </a-select>
          </a-form-item>
        </a-form>
        <a-button
          mb-4
          type="primary"
          @click="createNew"
          :disabled="!formRef.categoryId || status != State.init"
        >
          新建
        </a-button>
        <a-table
          size="small"
          :pagination="false"
          :data-source="splits"
          :columns="conditionColumns"
          @resize-column="resize"
        >
          <template #bodyCell="{ column, record, value, index }">
            <template v-if="column.dataIndex === 'categoryName'">
              <a-input
                ref="inputRef"
                placeholder="请输入"
                v-model:value.trim="inputValue"
                :maxlength="20"
                v-if="
                  (status == State.create || status == State.modify) &&
                  inputOriginValue == value
                "
                @press-enter="inputRef?.blur()"
                @blur="saveInput"
              ></a-input>
              <span v-else
                >{{ value }}

                <a-button type="link" @click="modify(record)"
                  ><edit-outlined
                /></a-button>
              </span>
            </template>
            <div flex flex-wrap gap-y-2 v-if="column.dataIndex == 'option'">
              <a-tag
                v-for="(item, idx) in (record as SplitItem).splitConditionOptions"
                :key="item.option_name"
                closable
                @close.prevent="record.splitConditionOptions.splice(idx, 1)"
              >
                {{ item.option_name }}
              </a-tag>
            </div>
            <a-button
              v-if="column.dataIndex === 'action'"
              type="link"
              @click="splits.splice(index, 1)"
            >
              删除
            </a-button>
          </template>
        </a-table>
      </div>

      <div>
        <a-form>
          <a-form-item label="对应条件" v-bind="validateInfos.conditionCode">
            <a-select
              :value="currentCondition?.spec_code"
              :options="conditionList"
              :field-names="{ label: 'spec_name', value: 'spec_code' }"
              @change="changeCondition"
              allow-clear
            ></a-select>
          </a-form-item>
        </a-form>
        <a-popconfirm
          title="关联类目"
          @confirm="batchConfirmTarget"
          @open-change="closePopconfirm"
          :disabled="!splits.length || !selectedRowKeys.length"
        >
          <template #description>
            <a-select
              placeholder="请选择"
              :value="target?.categoryName"
              w-200px
              :get-popup-container="el => el.parentElement"
              @change="changeTarget"
            >
              <a-select-option
                v-for="item in splits"
                :key="item.categoryName"
                :value="item.categoryName"
              >
                {{ item.categoryName }}
              </a-select-option>
            </a-select>
          </template>
          <a-button
            type="primary"
            :disabled="!splits.length || !selectedRowKeys.length"
            mb-4
            >关联类目</a-button
          >
        </a-popconfirm>
        <a-table
          size="small"
          :columns="optionColumns"
          :data-source="currentCondition.spec_options || []"
          :row-selection="{
            selectedRowKeys,
            onChange: changeSelects,
            getCheckboxProps: record => ({
              disabled: rowUsed(record),
            }),
          }"
          row-key="spec_option_value"
        >
          <template #bodyCell="{ column, record, value }">
            <template v-if="column.dataIndex === 'spec_option_name'">
              <check-circle-outlined
                text-success
                v-if="rowUsed(record as SpecOption)"
              />
              {{ value }}
            </template>
            <a-popconfirm
              title="关联类目"
              v-if="column.dataIndex === 'action'"
              @confirm="confirmTarget(record)"
              @open-change="closePopconfirm"
              :disabled="rowUsed(record as SpecOption)"
            >
              <template #description>
                <a-select
                  placeholder="请选择"
                  :value="target?.categoryName"
                  w-200px
                  :get-popup-container="el => el.parentElement"
                  @change="changeTarget"
                >
                  <a-select-option
                    v-for="item in splits"
                    :key="item.categoryName"
                    :value="item.categoryName"
                  >
                    {{ item.categoryName }}
                  </a-select-option>
                </a-select>
              </template>
              <a-button type="link" :disabled="rowUsed(record as SpecOption)">
                关联类目
              </a-button>
            </a-popconfirm>
          </template>
        </a-table>
      </div>
    </div>
  </a-modal>
</template>

<script lang="ts" setup>
import {
  fetchCategoryByWebsiteCode,
  fetchCategoryConditions,
} from '@/api/website';
import {
  CategroySplitItem,
  createCategorySplit,
  CreateSplitParams,
  modifyCategorySplits,
} from '@/api/split';
import { Category } from '@/types/category';
import { Spec, SpecOption } from '../Selection/type';
import { SplitItem, SplitItemOption } from './type';
import { EditOutlined, CheckCircleOutlined } from '@ant-design/icons-vue';
import { Modal } from 'ant-design-vue';

const emits = defineEmits<{
  ok: [];
}>();

const show = ref(false);
const isEdit = ref(false);

const categoryList = ref<Category[]>([]);
const conditionList = ref<Spec[]>([]);
const splits = ref<SplitItem[]>([]);

type FormRef = {
  websiteCode: string;
  categoryId?: string | number;
  conditionCode?: string | number;
};

const formRef = reactive<FormRef>({
  websiteCode: '',
  categoryId: undefined,
  conditionCode: undefined,
});
const formRules = reactive({
  categoryId: [{ required: true, message: '请选择' }],
  conditionCode: [{ required: true, message: '请选择' }],
});
const { validateInfos, validate, resetFields } = Form.useForm(
  formRef,
  formRules
);
const resize = (width, col) => {
  col.width = width;
};

const conditionColumns = ref([
  {
    title: '拆分类目',
    dataIndex: 'categoryName',
    width: 100,
    resizable: true,
  },
  {
    title: '对应选项',
    dataIndex: 'option',
    resizable: true,
    width: 300,
  },
  {
    title: '操作',
    dataIndex: 'action',
    width: '100px',
  },
]);

const optionColumns = ref([
  {
    title: '选项',
    dataIndex: 'spec_option_name',
  },
  {
    title: '操作',
    dataIndex: 'action',
    width: 100,
  },
]);

const currentCondition = computed(
  () =>
    conditionList.value.find(item => item.spec_code == formRef.conditionCode) ||
    ({} as Spec)
);
const currentCategory = computed(
  () =>
    categoryList.value.find(item => item.id == formRef.categoryId) ||
    ({} as Category)
);
const changeCategory = categoryId => {
  if (categoryId) {
    formRef.categoryId = categoryId;
    loadCondition();
  } else {
    conditionList.value = [];
    formRef.conditionCode = undefined;
  }
};
const loadCondition = async () => {
  const { categoryId, websiteCode } = formRef;
  // @ts-ignore
  const res = await fetchCategoryConditions({ websiteCode, categoryId });
  useRes(res, () => {
    conditionList.value = parseJson<Spec[]>(res.data, []);
    if (conditionList.value.length && !isEdit.value) {
      const [first] = conditionList.value;
      changeCondition(first.spec_code);
    }
  });
};

enum State {
  init,
  create,
  modify,
}
const inputRef = ref();
const inputOriginValue = ref('');
const inputValue = ref('');
const status = ref(State.init);
const createNew = () => {
  status.value = State.create;
  inputOriginValue.value = '';
  inputValue.value = '';
  splits.value.unshift({ categoryName: '', splitConditionOptions: [] });
  nextTick(() => {
    inputRef.value?.focus();
  });
};
const modify = record => {
  let _record = record as SplitItem;
  status.value = State.modify;
  inputOriginValue.value = _record.categoryName;
  inputValue.value = _record.categoryName;
  nextTick(() => {
    inputRef.value?.focus();
  });
};
const saveInput = () => {
  const idx = splits.value.findIndex(
    item => item.categoryName == inputOriginValue.value
  );
  if (!inputValue.value) {
    if (status.value == State.create) {
      splits.value.splice(idx, 1);
    } else if (status.value == State.modify) {
      // do nothing
    }
  } else {
    const sameIdx = splits.value.findIndex(
      (item, index) => item.categoryName == inputValue.value && index != idx
    );
    if (sameIdx > -1) {
      message.warning(`${inputValue.value}已存在`);
      if (status.value == State.create) {
        splits.value.splice(idx, 1);
      }
    } else {
      splits.value[idx].categoryName = inputValue.value;
    }
  }
  if (status.value == State.create) {
  }
  nextTick(() => {
    status.value = State.init;
  });
};

const getCategories = async () => {
  const res = await fetchCategoryByWebsiteCode({
    websiteCode: formRef.websiteCode,
  });
  useRes(res, () => {
    categoryList.value = res.data.categoryList;
  });
};

const add = async (websiteCode: string, categoryId) => {
  isEdit.value = false;
  show.value = true;
  formRef.websiteCode = websiteCode;
  await getCategories();
  if (categoryId) {
    changeCategory(Number(categoryId));
  }
};
const edit = async (websiteCode: string, record: CategroySplitItem) => {
  isEdit.value = true;
  show.value = true;
  formRef.websiteCode = websiteCode;
  const { originCategoryCode, splitConditionCode } = record;
  await getCategories();
  const _category = categoryList.value.find(
    item => item.categoryCode == originCategoryCode
  );
  if (_category) {
    formRef.categoryId = _category.id;
    await loadCondition();
    changeCondition(splitConditionCode);
    splits.value = record.splits.map(item => {
      return {
        categoryName: item.categoryName,
        splitConditionOptions: parseJson(item.splitConditionOptions, []),
      };
    });
  }
};

const changeCondition = code => {
  if (code == formRef.conditionCode) return;
  if (splits.value.length) {
    Modal.confirm({
      title: '提示',
      content: '切换条件将丢失当前未保存的数据，是否继续',
      onOk() {
        splits.value = [];
        if (code) {
          formRef.conditionCode = code;
        } else {
          formRef.conditionCode = undefined;
        }
      },
    });
  } else {
    if (code) {
      formRef.conditionCode = code;
    } else {
      formRef.conditionCode = undefined;
    }
  }
};

const target = ref<SplitItem>();
const changeTarget = key => {
  target.value = splits.value.find(item => item.categoryName == key);
};
const confirmTarget = record => {
  let _record = record as SpecOption;
  if (rowUsed(_record)) return;
  const { spec_option_name, spec_option_value } = _record;
  const _option: SplitItemOption = {
    option_name: spec_option_name,
    option_value: spec_option_value,
  };
  if (target.value) {
    if (
      !target.value.splitConditionOptions.some(item =>
        compare(item, _option, ['option_name', 'option_value'])
      )
    ) {
      target.value.splitConditionOptions.push(_option);
    }
  }
};
const closePopconfirm = (open: boolean) => {
  if (!open) {
    target.value = undefined;
  }
};
const batchConfirmTarget = () => {
  while (selectedRows.value.length) {
    const item = selectedRows.value.pop();
    if (item) {
      confirmTarget(item);
    }
  }
  selectedRowKeys.value = [];
};

const optionMap = computed(() => {
  const map: Map<string, string> = new Map();
  for (let item of splits.value) {
    for (let option of item.splitConditionOptions) {
      const { option_name, option_value } = option;
      map.set(option_name + option_value, item.categoryName);
    }
  }
  return map;
});

// const disableOption = (record: SpecOption, categoryName: string) => {
//   return (
//     optionMap.value.get(record.spec_option_name + record.spec_option_value) ==
//     categoryName
//   );
// };
const rowUsed = (record: SpecOption) => {
  return optionMap.value.has(
    record.spec_option_name + record.spec_option_value
  );
};

const selectedRowKeys = ref<string[]>([]);
const selectedRows = ref<SpecOption[]>([]);
const changeSelects = (keys, options) => {
  selectedRowKeys.value = keys;
  selectedRows.value = options;
};

const genParams = () => {
  const params = {} as CreateSplitParams;
  const _splits = splits.value.map(item => {
    return {
      id: item.id,
      categoryName: item.categoryName,
      splitConditionOptions: JSON.stringify(item.splitConditionOptions),
    };
  });
  params.originCategoryCode = currentCategory.value?.categoryCode || '';
  params.originCategoryName = currentCategory.value?.categoryName || '';
  params.splitConditionCode = currentCondition.value?.spec_code || '';
  params.splitConditionName = currentCondition.value?.spec_name || '';
  params.splits = _splits;
  params.websiteCode = formRef.websiteCode;
  return params;
};
const confirm = () => {
  validate().then(async () => {
    if (isEdit.value) {
      const res = await modifyCategorySplits(genParams());
      useRes(res, () => {
        message.success('修改成功');
        show.value = false;
        emits('ok');
      });
    } else {
      const res = await createCategorySplit(genParams());
      useRes(res, () => {
        message.success('保存成功');
        show.value = false;
      });
      emits('ok');
    }
  });
};
const afterClose = () => {
  delete formRef.categoryId;
  delete formRef.conditionCode;
  selectedRowKeys.value = [];
  selectedRows.value = [];
  splits.value = [];
  resetFields();
};
defineExpose({
  add,
  edit,
});
</script>
